// Local filesystem model header
// Copyright 2005 (C) Ralph Thomas

#ifndef FILE_MODEL_H
#define FILE_MODEL_H

#include <model/model.h>
#include <model/collection.h>
#include <model/internal/receiverHelper.h>
#include <model/internal/url.h>
#include <model/internal/sort.h>
#include <boost/filesystem/path.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/shared_ptr.hpp>
#include <toolkit/icon.h>
#include <map>

namespace model {
	class thumbnailThread;
	class thumbLoadQueue;
	//
	/// The fileModel uses boost::filesystem to allow access to the local
	/// filesystem. It can represent both files and directories; eventually
	/// it will be able to return the correct mime type for each file.
	///
	/// The model *should* report changes to the filesystem as they happen,
	/// however currently there is no standard way to be informed of these
	/// in a cross platform manner (so a notification library may be
	/// written).
	//
	class fileModel : public model {
		typedef std::map<std::string, fileModel*>	fileMap;
		typedef boost::recursive_mutex::scoped_lock	lock;
		typedef boost::recursive_mutex			mutex;
		static fileMap	_fileMap;	///< Already created file models
		unsigned int	_refCount;	///< Reference count of model.
		receiverHelper	_receivers;	///< All subscribed.
		std::string		_theUrl;	///< The URL requested.
		boost::filesystem::path _path;	///< The path we're representing
		unsigned int	_error;		///< Is there any error?
		std::string	_contents;	///< The contents of the model.
		std::string	_type;		///< Cached model MIME type.
		adobe::value_t	_icon;		///< Our icon, if created.
		bool		_scheduled;	///< Icon already requested?
		thumbnailThread*_thread;	///< Thumbnail-making thread.
		sorter		_children;	///< Child sorter.
		mutable mutex	_mutex; ///< For thumb thread.
		boost::shared_ptr<thumbLoadQueue>	_loadQueue;
		//
		// fileModel( const url* theUrl )
		//
		/// Create a new fileModel from the given URL. The URL should
		/// be on localhost. The fileModel can't use off-host files.
		///
		/// \param	path		the file to represent.
		//
		fileModel( const boost::filesystem::path& path, thumbnailThread* thumbThread );
		//
		// ~fileModel()
		//
		/// Virtual destructor; should only be invoked by release()
		/// when the reference count reaches zero. This method is only
		/// public to stop GCC from complaining.
		//
		virtual ~fileModel();
		//
		// bool init()
		//
		/// Initialize the model and make it ready to use. Even if the
		/// file doesn't exist then the function returns true (and the
		/// error is flagged). This is so that errors can correctly be
		/// reported.
		///
		/// This function only returns false if the URL points to
		/// another host.
		///
		/// \return	true if the model may be returned by the factory,
		///		false otherwise.
		//
		bool init();
		//
		// void _childNotify( const std::string& child, const std::string& attr,
		//	const adobe::value_t& value )
		//
		/// This function is invoked by logical children of this model who wish
		/// to communicate that they have changed some attribute. This is useful
		/// for parent models who wish to maintain a sorted list of children.
		///
		/// \param	child	the URL of the child which had an attribute change.
		/// \param	attr	the name of the attribute which changed.
		/// \param	value	the new value of the changed attribute.
		//
		void _childNotify( const std::string& child, const std::string& attr,
			const adobe::value_t& value );
		//
		// void _weakParentNotify( const std::string& attr )
		//
		/// This private method is used by child file models to notify parents
		/// of changes, if the parent model actually exists. If the parent
		/// does not exist then no notification is generated (and the parent
		/// model is not created ever).
		///
		/// \param	attr	the attribute to notify the parent about.
		//
		void _weakParentNotify( const std::string& attr, const adobe::value_t&
			       value );
		//
		// std::string getParentUrl() const
		// 
		/// Return the URL of this model's parent.
		///
		/// \return	the URL of this model's parent.
		//
		std::string _getParentUrl() const;
		//
		// static std::string _buildUrl( const path& p )
		// 
		/// Build a complete URL (in string form) from the given Boost
		/// Filesystem path.
		///
		/// \param	p	the path to build a URL from.
		/// \return	the URL for the given path.
		//
		static std::string _buildUrl( const boost::filesystem::path& p );
	  public:
		//
		// static model* fromString( std::string serialized )
		//
		/// Create a fileModel from the given string. If the fileModel
		/// cannot be created then 0 is returned, otherwise the
		/// fileModel is returned.
		///
		/// \param	serialized	the URL to create a file model
		///				from.
		//
		static fileModel* fromString( const std::string& serialized );
		//
		// from model/model.h
		//
		virtual model* retain() const;
		virtual void release();
		virtual void subscribe( receiver* r );
		virtual void unsubscribe( const receiver* r );
		virtual adobe::value_t getAttribute( const std::string& attrName )
			const;
		virtual void setAttribute( const std::string& attrName,
			const adobe::value_t& val );
		virtual adobe::value_t execute( const std::string& action,
			const adobe::value_t& arg );
		//
		/// Called by the thumbnailThread to indicate that an icon
		/// thumbnail has been generated.
		//
		void iconComplete( const adobe::value_t& icon );
	};
};

#endif

